Skip to content

feat(core/inlines): support [[[SPEC#id]]] for cross-spec section links#5146

Merged
marcoscaceres merged 53 commits into
mainfrom
feat/inlines-cross-spec
May 14, 2026
Merged

feat(core/inlines): support [[[SPEC#id]]] for cross-spec section links#5146
marcoscaceres merged 53 commits into
mainfrom
feat/inlines-cross-spec

Conversation

@marcoscaceres

Copy link
Copy Markdown
Contributor

Summary

  • Extends the [[[...]]] inline expansion syntax to allow [[[SPEC#fragment]]]
  • Resolves to the spec's href from the bibliography with the #fragment appended
  • Example: [[[fetch#data-fetch]]] → link to the Fetch spec's #data-fetch section, with link text taken from the spec title

Test plan

  • Run unit tests: pnpm test:unit
  • Verify [[[fetch#data-fetch]]] produces a link to https://fetch.spec.whatwg.org/#data-fetch

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Extends ReSpec’s [[[...]]] inline expansion parsing so authors can cite a spec and link directly to a section using a fragment (e.g., [[[fetch#data-fetch]]]), leveraging existing data-cite fragment handling.

Changes:

  • Updated the [[[...]]] inline-expansion regex to allow an optional #fragment suffix.
  • Added a unit test asserting that [[[fetch#data-fetch]]] resolves to the spec URL with the fragment and uses the spec title as link text.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/core/inlines.js Broadens inlineExpansion matching to include SPEC#fragment forms.
tests/spec/core/inlines-spec.js Adds coverage for cross-spec section linking via [[[SPEC#id]]].

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/core/inlines.js Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/spec/core/inlines-spec.js Outdated
@marcoscaceres

Copy link
Copy Markdown
Contributor Author

@sidvishnoi Good point. The spec title alone isn't useful for section-level links. The intended behavior for [[[fetch#cookie-header]]] is to display the actual heading text, like "§ 3.1.1 Cookie header (Fetch Standard)".

The data for this is available in w3c/webref's headings data. I've opened speced/respec-web-services#469 to add a /xref/headings endpoint that looks up {spec, id}{title, number, href, specTitle}.

Holding this PR until the headings API is available and the inlines.js expansion can use real heading text. Will also add alias support ([[[fetch#cookie-header|cookie handling]]]).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/core/data-cite.js
Comment thread src/core/data-cite.js Outdated
Comment thread src/core/data-cite.js Outdated
Comment thread src/core/data-cite.js Outdated
Comment thread tests/spec/core/inlines-spec.js
@marcoscaceres

Copy link
Copy Markdown
Contributor Author

@copilot Can you check and fix any issues identified by ci?

auto-merge was automatically disabled April 15, 2026 15:56

Head branch was pushed to by a user without write access

Copilot AI commented Apr 15, 2026

Copy link
Copy Markdown
Contributor

@copilot Can you check and fix any issues identified by ci?

Fixed in 8c873cf. The CI failures were caused by my data-lt alias handling in data-cite.js applying unconditionally to any element with data-lt, including IDL references from inline-idl-parser.js (which use data-lt as a lookup term but have <code> child content). This corrupted IDL link text — e.g., addEventListener(type, callback) was duplicated because elem.textContent = elem.dataset.lt replaced the <code> children of <a>, then the sibling <code>(type, callback)</code> was appended again.

The fix: guard with elem.textContent === "" so alias text is only applied to empty elements (triple-bracket expansions), not IDL references that already have child content.

@marcoscaceres

Copy link
Copy Markdown
Contributor Author

@copilot, can you fix any outstanding comments and resolve any that have already been addressed?

Copilot AI commented Apr 16, 2026

Copy link
Copy Markdown
Contributor

@copilot, can you fix any outstanding comments and resolve any that have already been addressed?

Done in 47181d8. Here's the status of each outstanding thread:

  • headingElements dead code — was already removed in a prior commit; no action needed.
  • Heading fetching scoping + heading text overwrite + <cite> sibling DOM shape — all three are addressed by removing the premature heading API integration (fetchHeadings, HEADINGS_API_URL, § N title text, <cite> sibling). The /xref/headings endpoint doesn't exist yet, so this is deferred to a follow-up PR when the API is ready. [[[fetch#data-fetch]]] now stably produces <a href="https://fetch.spec.whatwg.org/#data-fetch">Fetch Standard</a> with no network calls beyond biblio.

…o xref config, use local API in tests

- Remove data-cite-section; use data-cite-frag (citeFrag) for section fragment
- xref-headings.js: query a[data-cite-frag][data-matched-text] for section links
  and read conf.xref.headingApiUrl (nested under xref config)
- data-cite.js: drop citeSection from toCiteDetails; use citeFrag && matchedText
  to identify section links for alias-application skip
- dfn-index.js: drop citeFrag from inclusion condition — section links have no
  xrefType/linkType and no # in cite, so they're naturally excluded
- type-helper.d.ts: add headingApiUrl to xref object type, remove xrefHeadingsUrl
- tests: use xref.headingApiUrl local fixture for all [[[SPEC#id]]] tests;
  keep one production-API test; expand headings.json fixture with data-fetch entry

Agent-Logs-Url: https://github.com/speced/respec/sessions/aa32a927-c840-432a-a14e-e761677cb37d

Copilot AI commented May 13, 2026

Copy link
Copy Markdown
Contributor

@copilot When you finish the current session, can you make sure ci is passing and fix any issues?

Fixed in b09c8f8. There were 3 failing tests caused by the citeFrag refactor in 8aa424c:

  1. dfn-index.js guard — My earlier removal of citeFrag from the guard (1b27917) was based on the state before 8aa424c. Once section links started using citeFrag, regular dfn refs like <dfn data-cite="SPEC#dfn-predicate"> (which produce an inner <a> with only citeFrag, no xrefType/linkType) were wrongly excluded. Restored citeFrag to the guard, and added if (citeFrag && matchedText) continue to exclude section links (only they have both citeFrag and data-matched-text).

  2. Inlines test assertion#index-defined-elsewhere is always created when <section id="index"> exists. Changed to check #index-defined-elsewhere li[data-spec] entries instead.

@sidvishnoi sidvishnoi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot tests broken. Please address.

Comment thread src/core/xref-headings.js Outdated
…ach(clearHeadingsData) in tests

Agent-Logs-Url: https://github.com/speced/respec/sessions/8c82878b-0473-4392-a75b-8f86395664f7

Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com>

Copilot AI commented May 14, 2026

Copy link
Copy Markdown
Contributor

@copilot tests broken. Please address.

The test failures from 8aa424c were fixed in b09c8f8. The skipCache coupling issue flagged in the code review comment has been addressed in 3cb371f — cache behavior no longer depends on the API URL.

Comment thread src/core/inlines.js Outdated
Comment thread src/core/inlines.js Outdated
Comment thread src/core/xref-headings.js Outdated
Comment thread src/core/xref-headings.js
Comment thread src/core/xref-headings.js Outdated
@marcoscaceres

Copy link
Copy Markdown
Contributor Author

@copilot can you fix the issues CI found?

Copilot AI and others added 2 commits May 14, 2026 12:20
…st to use local fixture

Agent-Logs-Url: https://github.com/speced/respec/sessions/894f7dcc-7649-4771-a614-beba3fd743da

Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com>
…ning

Agent-Logs-Url: https://github.com/speced/respec/sessions/894f7dcc-7649-4771-a614-beba3fd743da

Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com>

Copilot AI commented May 14, 2026

Copy link
Copy Markdown
Contributor

@copilot can you fix the issues CI found?

Fixed in f7a04da. The failing test ("uses heading text from API for [[[SPEC#id]]] when available") was hitting the production API and timing out in CI. Converted it to use the local fixture (/tests/data/headings.json) — consistent with all other xref heading tests. Assertions are now deterministic (exact "4 Fetching" / "4 " for secno).

@sidvishnoi sidvishnoi left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Few nits.

Comment thread src/core/xref-headings.js Outdated
const { result = [] } = await res.json();
/** @type {Map<string, HeadingInfo>} */
const fetched = new Map(
/** @type {{ spec: string, id: string, title: string, number: string | null, error?: boolean }[]} */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: extract this to a typedef.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ff74aa7 — added @typedef HeadingApiResultEntry and merged it with the existing HeadingInfo typedef block. The inline @type cast in fetchHeadingTexts now uses /** @type {HeadingApiResultEntry[]} */.

Comment thread src/core/xref-headings.js Outdated
* Must run after core/data-cite (so elements have href and spec-title fallback).
* @param {Conf} conf
*/
export async function run(conf) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: let's move this run() function to top (main on top, dependencies below it), matching rest of the plugins.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ff74aa7run() is now the first exported function, with getApiUrl(), fetchHeadingTexts(), and setHeadingContent() following it.

Comment thread src/core/xref-headings.js Outdated
Comment on lines +112 to +121
const xrefConf =
typeof conf.xref === "object" &&
conf.xref !== null &&
!Array.isArray(conf.xref)
? conf.xref
: {};
const apiUrl =
typeof xrefConf.headingApiUrl === "string"
? xrefConf.headingApiUrl
: HEADINGS_API_URL;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: extract this into a function, getApiUrl(conf), so it's cleaner.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in ff74aa7 — extracted getApiUrl(conf) helper function. run() now calls it with a single const apiUrl = getApiUrl(conf) line.

@marcoscaceres

Copy link
Copy Markdown
Contributor Author

@copilot fix the nits?

…piUrl()

Agent-Logs-Url: https://github.com/speced/respec/sessions/3046c1c9-db26-4cee-9e17-15e70a809936

Co-authored-by: marcoscaceres <870154+marcoscaceres@users.noreply.github.com>

Copilot AI commented May 14, 2026

Copy link
Copy Markdown
Contributor

@copilot fix the nits?

Done in ff74aa7. All three nits addressed: @typedef HeadingApiResultEntry extracted, run() moved to top, getApiUrl(conf) helper extracted.

@copilot can you fix the issues CI found?

CI is passing on feat/inlines-cross-spec (Node CI, CodeQL, PR title check all green as of the latest push).

@marcoscaceres
marcoscaceres merged commit 216b294 into main May 14, 2026
9 checks passed
@marcoscaceres
marcoscaceres deleted the feat/inlines-cross-spec branch May 14, 2026 12:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants